package wyszukiwanieLukow;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

import typydanych.Obrazek;

public class WyszukiwanieLukow {

	private int wysokoscPasuPrzeszukiwania;
	private double dopuszczalnyBladAproksymacji;

	private static final int BRAK_LUKOW = 0;
	private static final int LUK_NA_DOLE = 1;
	private static final int LUK_NA_GORZE = 2;
	private static final int LUK_NA_DOLE_I_GORZE = 3;
	private WykrywanieLinii wykrywanieLinii;
	private int progowanieSzumow;

	public WyszukiwanieLukow() {
		wykrywanieLinii = new WykrywanieLinii();
		wysokoscPasuPrzeszukiwania = 4;
		dopuszczalnyBladAproksymacji = 0.33;
		progowanieSzumow = 40;
	}

	public WyszukiwanieLukow(int wysokoscPasuPrzeszukiwania,
			double dopuszczalnyBladAproksymacji, int progowanieSzumow) {
		this.wysokoscPasuPrzeszukiwania = wysokoscPasuPrzeszukiwania;
		this.dopuszczalnyBladAproksymacji = dopuszczalnyBladAproksymacji;
		this.progowanieSzumow = progowanieSzumow;
		wykrywanieLinii = new WykrywanieLinii();
	}

	public int getWysokoscPasuPrzeszukiwania() {
		return wysokoscPasuPrzeszukiwania;
	}

	public void setWysokoscPasuPrzeszukiwania(int wysokoscPasuPrzeszukiwania) {
		this.wysokoscPasuPrzeszukiwania = wysokoscPasuPrzeszukiwania;
	}

	public int getProgowanieSzumow() {
		return progowanieSzumow;
	}

	public void setProgowanieSzumow(int progowanieSzumow) {
		this.progowanieSzumow = progowanieSzumow;
	}
	
	public double getDopuszczalnyBladAproksymacji() {
		return dopuszczalnyBladAproksymacji;
	}

	public void setDopuszczalnyBladAproksymacji(double dopuszczalnyBladAproksymacji) {
		this.dopuszczalnyBladAproksymacji = dopuszczalnyBladAproksymacji;
	}

	/**
	 * Metoda przyjmuje obrazek i wyszukuje luk w gornym i dolnym obszarze.
	 * Wysokosc pasa przeszukiwnia mozna zdefiniowac za pomoca pola klasy. Jako
	 * rezultat metoda zwraca okreslona liczbe, ktora w jakich sposob
	 * charakteryzuje istnienie lukow na obrazku.
	 * 
	 * @param obrazek
	 * @return
	 */
	public int rozpoznaj(Obrazek obrazek) {

		boolean lukNaGorze = przeszukajGore(obrazek);
		boolean lukNaDole = przeszukajDol(obrazek);

		//System.out.println("lukNaGorze: "+lukNaGorze);
		//System.out.println("lukNaDole: "+lukNaDole);
		if (lukNaDole && lukNaGorze) {
			return LUK_NA_DOLE_I_GORZE;

		} else if (lukNaDole && !lukNaGorze) {
			return LUK_NA_DOLE;

		} else if (!lukNaDole && lukNaGorze) {
			return LUK_NA_GORZE;

		} else
			// if(!lukNaDole && !lukNaGorze){
			return BRAK_LUKOW;
	}

	// ==============================================================================================
	private boolean przeszukajGore(Obrazek obrazek) {

		List<Point> punktyNalezaceDoCalejLinii;
		Linia lewaCzesc = null;
		Linia prawaCzesc = null;
		double bladAproksymacjiCalejLinii;

		punktyNalezaceDoCalejLinii = wykrywanieLinii
				.zbierzPunktyNalezaceDoCzesciLuku(obrazek, progowanieSzumow, 0,
						obrazek.ROZMIAR, obrazek.getObszarCyfry().getGora(), obrazek.getObszarCyfry().getGora()+wysokoscPasuPrzeszukiwania);
		
		if (punktyNalezaceDoCalejLinii == null) {
			return false; // w przypadku gdy wystepuje nieciaglosc lub nie
							// znaleziono zadnego punktu w obszarze
		}
		bladAproksymacjiCalejLinii = wykrywanieLinii
				.policzBladAproksymacji(punktyNalezaceDoCalejLinii);
		
		//System.out.println("---\nGORA:  " + bladAproksymacjiCalejLinii);

		if (bladAproksymacjiCalejLinii <= dopuszczalnyBladAproksymacji) {
			// znalezione linia jest prosta a nie lukiem
			return false;
			
		} else {
			// trzeba zbadac czy luk jest poprawny
			lewaCzesc = zbadajObszar(obrazek, 0, obrazek.ROZMIAR / 2, obrazek.getObszarCyfry().getGora(), obrazek.getObszarCyfry().getGora()+wysokoscPasuPrzeszukiwania);
			prawaCzesc = zbadajObszar(obrazek, obrazek.ROZMIAR / 2, obrazek.ROZMIAR, obrazek.getObszarCyfry().getGora(), obrazek.getObszarCyfry().getGora()+wysokoscPasuPrzeszukiwania);
			//System.out.println("lewaCzesc:  " + lewaCzesc);
			//System.out.println("prawaCzesc:  " + prawaCzesc);
		}
		return akceptacjaGornegoLuku(lewaCzesc, prawaCzesc);
	}

	// ==============================================================================================

	private boolean przeszukajDol(Obrazek obrazek) {
		List<Point> punktyNalezaceDoCalejLinii;
		Linia lewaCzesc = null;
		Linia prawaCzesc = null;
		double bladAproksymacjiCalejLinii;

		punktyNalezaceDoCalejLinii = wykrywanieLinii.zbierzPunktyNalezaceDoCzesciLuku(obrazek, progowanieSzumow, 0,obrazek.ROZMIAR, obrazek.getObszarCyfry().getDol()-wysokoscPasuPrzeszukiwania, obrazek.getObszarCyfry().getDol());
		
		if (punktyNalezaceDoCalejLinii == null) {
			return false; // w przypadku gdy wystepuje nieciaglosc lub nie
							// znaleziono zadnego punktu w obszarze
		}
		bladAproksymacjiCalejLinii = wykrywanieLinii.policzBladAproksymacji(punktyNalezaceDoCalejLinii);
		
		//System.out.println("---\nDOL:  " + bladAproksymacjiCalejLinii);

		if (bladAproksymacjiCalejLinii <= dopuszczalnyBladAproksymacji) {
			// znalezione linia jest prosta a nie lukiem
			return false;
			
		} else {
			// trzeba zbadac czy luk jest poprawny
			lewaCzesc = zbadajObszar(obrazek, 0, obrazek.ROZMIAR / 2, obrazek.getObszarCyfry().getDol()-wysokoscPasuPrzeszukiwania, obrazek.getObszarCyfry().getDol());
			prawaCzesc = zbadajObszar(obrazek, obrazek.ROZMIAR / 2,obrazek.ROZMIAR, obrazek.getObszarCyfry().getDol()-wysokoscPasuPrzeszukiwania, obrazek.getObszarCyfry().getDol());
			//System.out.println("lewaCzesc:  " + lewaCzesc);
			//System.out.println("prawaCzesc:  " + prawaCzesc);
		}
		return akceptacjaDolnegoLuku(lewaCzesc, prawaCzesc);
	}

	// ==============================================================================================
	private Linia zbadajObszar(Obrazek obrazek, int poczatekX, int koniecX,
			int poczatekY, int koniecY) {
		Linia linia;
		List<Point> punktyNalezaceLinii;

		punktyNalezaceLinii = wykrywanieLinii.zbierzPunktyNalezaceDoCzesciLuku(obrazek, progowanieSzumow, poczatekX, koniecX, poczatekY, koniecY);
		if (punktyNalezaceLinii == null) {
			return null; // w przypadku gdy wystepuje nieciaglosc lub nie
							// znaleziono zadnego punktu w obszarze
		}
		linia = wykrywanieLinii.utworzLinieZPunktow(punktyNalezaceLinii);
		linia.bladAproksymacji = wykrywanieLinii
				.policzBladAproksymacji(punktyNalezaceLinii);
		return linia;
	}

	// ==============================================================================================
	private boolean akceptacjaDolnegoLuku(Linia lewaCzesc, Linia prawaCzesc) {

		int bladPiksela = 1;
		if (lewaCzesc == null || prawaCzesc == null)
			return false;

		if (lewaCzesc.sy - bladPiksela < lewaCzesc.ey && prawaCzesc.sy > prawaCzesc.ey - bladPiksela) {
			return true;
		}
		return false;
	}

	// ==============================================================================================
	private boolean akceptacjaGornegoLuku(Linia lewaCzesc, Linia prawaCzesc) {

		int bladPiksela = 1;
		if (lewaCzesc == null || prawaCzesc == null)
			return false;

		if (lewaCzesc.sy + bladPiksela> lewaCzesc.ey && prawaCzesc.sy < prawaCzesc.ey + bladPiksela) {
			return true;
		}
		return false;
	}
}
